#pragma once
#include<vector>
class Head
{
public:
	enum class PosType
	{
		X,
		Y
	};
	enum class Direction
	{
		Up,
		Down,
		Right,
		Left
	};


	Head(int tx,int ty)
	{
		initx = tx;
		inity = ty;
		x = tx;
		y = ty;
		lastx = x - 1;
		lasty = y;
		moving_direction = Direction::Right;
	}
	~Head() = default;

	void SetPos(int tx,int ty)
	{
		x = tx;
		y = ty;
	}
	void SetLastPos(int tx, int ty)
	{
		lastx = tx;
		lasty = ty;
	}

	int GetPosX()
	{
		return x;
	}

	int GetPosY()
	{
		return y;
	}

	int GetLastPosX()
	{
		return lastx;
	}

	int GetLastPosY()
	{
		return lasty;
	}

	void ChangePos(PosType type, int delta)
	{
		switch (type)
		{
		case PosType::X:
			x += delta;
			break;
		case PosType::Y:
			y += delta;
			break;
		default:
			break;
		}
	}

	void ChangeDirection(Direction d)
	{
		switch (d)
		{
		case Direction::Left:
			if (x - 1 != lastx)
			{
				moving_direction = d;
			}
			break;
		case Direction::Right:
			if (x + 1 != lastx)
			{
				moving_direction = d;
			}
			break;
		case Direction::Up:
			if (y - 1 != lasty)
			{
				moving_direction = d;
			}
			break;
		case Direction::Down:
			if (y + 1 != lasty)
			{
				moving_direction = d;
			}
			break;
		default:
			break;
		}
		
	}

	void move()
	{
		lastx = x;
		lasty = y;
		switch (moving_direction)
		{
		case Direction::Up:
			y--;
			break;
		case Direction::Down:
			y++;
			break;
		case Direction::Right:
			x++;
			break;
		case Direction::Left:
			x--;
			break;
		default:
			break;
		}
	}

	void Reset()
	{
		x = initx;
		y = inity;
		lastx = x - 1;
		lasty = y;
		moving_direction = Direction::Right;
	}

private:
	int x, y;
	int lastx, lasty;
	int initx, inity;
	Direction moving_direction;
};

extern Head snakehead;

class BodyCell
{
public:
    static const int MAX_HISTORY = 5;  // 保留最近5个位置
    
    struct Position {
        int x, y;
    };
    
    BodyCell() = default;
    ~BodyCell() = default;

    int GetPosX() { return x; }
    int GetPosY() { return y; }

    int GetLastPosX() { return lastx; }
    int GetLastPosY() { return lasty; }

    void SetPos(int tx, int ty) {
        x = tx;
        y = ty;
        // 记录历史位置
        positionHistory.insert(positionHistory.begin(), {tx, ty});
        if (positionHistory.size() > MAX_HISTORY) {
            positionHistory.pop_back();
        }
    }

    void SetLastPos(int tx, int ty) {
        lastx = tx;
        lasty = ty;
    }

    std::vector<Position> GetPositionHistory() const {
        return positionHistory;
    }
	bool CollideHead()
	{
		if (GetPosX() == snakehead.GetPosX() && GetPosY() == snakehead.GetPosY() )
		{
			return true;
		}
		return false;
	}
private:
    int x, y;
    int lastx, lasty;
    std::vector<Position> positionHistory;
};

class Body
{
public:
	BodyCell& operator[](int index)
	{
		return BodyAdress[index];
	}

	Body(int maxLength,int firstbodyX,int firstbodyY,int secondbodyX,int secondbodyY)
	{
		Length = 2;
		mLength = maxLength;
		fx = firstbodyX;
		fy = firstbodyY;
		sx = secondbodyX;
		sy = secondbodyY;
		BodyAdress = new BodyCell[maxLength];
		BodyAdress[0].SetPos(firstbodyX, firstbodyY);
		BodyAdress[0].SetLastPos(firstbodyX, firstbodyY);
		BodyAdress[1].SetPos(secondbodyX, secondbodyY);
		BodyAdress[1].SetLastPos(secondbodyX,secondbodyY);
	}

	~Body()
	{
		delete[] BodyAdress;
	}

	int GetBodyLength()
	{
		return Length;
	}

	void move(int headlastx,int headlasty)
	{
		BodyAdress[0].SetLastPos(BodyAdress[0].GetPosX(), BodyAdress[0].GetPosY());
		BodyAdress[0].SetPos(headlastx, headlasty);
		for (int i = 1; i < Length; i++)
		{
			BodyAdress[i].SetLastPos(BodyAdress[i].GetPosX(), BodyAdress[i].GetPosY());
			BodyAdress[i].SetPos(BodyAdress[i - 1].GetLastPosX(), BodyAdress[i - 1].GetLastPosY());
		}
	}

	void grow()
	{
		Length++;
	}

	bool CollideHead()
	{
		for (int i = 0; i < Length; i++)
		{
			if (BodyAdress[i].CollideHead())
			{
				return true;
			}
		}
		return false;
	}

	void Reset()
	{
		delete[] BodyAdress;
		Length = 2;
		BodyAdress = new BodyCell[mLength];
		BodyAdress[0].SetPos(fx, fy);
		BodyAdress[0].SetLastPos(fx, fy);
		BodyAdress[1].SetPos(sx, sy);
		BodyAdress[1].SetLastPos(sx, sy);
	}

private:
	int Length;
	int fx, fy, sx, sy;
	int mLength;
	BodyCell* BodyAdress;
};